#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import User 
from documents.modelfields import ItemTypeField

from taggit.managers import TaggableManager

class Lecturer(models.Model):
    """
    Model for a Lecturer
    """
    
    first_name = models.CharField(max_length=128)
    last_name = models.CharField(max_length=128)
    
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
    
    def __unicode__(self):
        return self.last_name + ', ' + self.first_name
        
class Semester(models.Model):
    """     
    Model for a Semester
    This is a seperate model because internationally there are different terms.
    It introduces a bit of modularity for future extension to other universities.
    """

    start = models.DateField()
    end = models.DateField()
    
    class Meta:
        # Set a descending order => newest Semesters at top
        ordering = ('-start', )
    
    def get_short(self):
        """
        Returns "[year][SS/WS]" for a Semester
        """
        
        # start and end have the same year => Summersemester
        # else => Wintersemester
        if(self.start.year == self.end.year):
            return unicode(self.start.year) + 'SS'
        
        return unicode(self.start.year) + 'WS'
    
    def __unicode__(self):
        """
        Returns "[years] [SS/WS]" for a Semester
        """
        
        # start and end have the same year => Summersemester
        # else => Wintersemester
        if(self.start.year == self.end.year):
            return unicode(self.start.year) + ' SS'
        
        return unicode(self.start.year) + '/' + unicode(self.end.year) + ' WS'

class Faculty(models.Model):
    """
    Model for a Faculty
    TODO - Won't have: For future extension here should be a new field
    referencing a university.
    """
    
    name = models.CharField(max_length=128, unique=True)
    
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
    
    activated = models.BooleanField(default = True)
    
    date = models.DateField(auto_now_add = True)
    
    def __unicode__(self):
        return self.name
    
    def has_perm(self, user_obj, perm):
        """
        Grants change/delete permission if the user has added the Faculty and no item has been added yet
        """
        if (perm == 'documents.change_faculty') or (perm == 'documents.delete_faculty'):
            return (user_obj == self.user) and (len(self.module_set.all()) < 1)
        return False

class Module(models.Model):
    """
    Model for a module
    If you e.g. have one module featuring a seminar, exercise and
    lecture this is one item
    """
    
    name = models.CharField(max_length=128)
    faculty = models.ForeignKey(Faculty)
    #term = models.ManyToManyField(Semester, through='ModuleTerm')
    
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
    
    activated = models.BooleanField(default = False)
    
    date = models.DateField(auto_now_add = True)
    
    def get_short(self):
        """
        Makes the Module short: Takes the upper case letters
        of the words an concatenates them (in lower case)
        'Entwurf und Analyse von Algorithmen' => 'eaa'
        'Computergraphik' => 'c'
        """
        words = self.name.split()
        short = ''
        for word in words:
            letter = word[0:1]
            if(letter.isupper()):
                short = short + (word[0:1]).lower()
        if short != '':
            return short
        short = (words[0])[0:1]
        if short.islower():
            return short
        return 'n'
    
    def __unicode__(self):
        return self.name
    
    def has_perm(self, user_obj, perm):
        """
        Grants change/delete permission if the user has added the Module and no item has been added yet
        """
        if (perm == 'documents.change_module') or (perm == 'documents.delete_module'):
            return (user_obj == self.user) and (len(self.moduleterm_set.all()) < 1)
        return False
    
    
class ModuleTerm(models.Model):
    """
    Introduction of a complex model of module terms.
    This model is defined as part of the ManyToMany relationship between
    Module and Semester.
    It also includes the lecturer who lectures this lecture in this term
    """
    
    module = models.ForeignKey(Module)
    semester = models.ForeignKey(Semester)
    
    #null possible because else there is a non stopping situation - work around. 
    lecturer = models.ForeignKey(Lecturer, blank=True, null=True)
    
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
    
    activated = models.BooleanField(default = False)
    
    date = models.DateField(auto_now_add = True)
    
    def __unicode__(self):
        return unicode(self.module) + " " + unicode(self.semester)
    
    @staticmethod
    def delete_handler(instance, **kwargs):
        """
        Deletes dead lecturers
        """
        if isinstance(instance, ModuleTerm):
            
            # on_delete: set_null
            instance.lecturer = None
            # calling save now deletes the lecturer if necessary
            instance.save()
    
    def save(self, *args, **kwargs):
        """
        Makes sure dead lecturers get deleted
        """
        try:
            old_lecturer = ModuleTerm.objects.get(id = self.id).lecturer
        
            # delete from db
            super(ModuleTerm, self).save(*args, **kwargs)
        
            # make sure dead lecturers get deleted
            if not old_lecturer.moduleterm_set.exists():
                old_lecturer.delete()
        except ModuleTerm.DoesNotExist:
            # delete from db
            super(ModuleTerm, self).save(*args, **kwargs)
            
    def has_perm(self, user_obj, perm):
        """
        Grants change/delete permission if the user has added the ModuleTerm and no item has been added yet
        """
        if (perm == 'documents.change_moduleterm') or (perm == 'documents.delete_moduleterm'):
            return (user_obj == self.user) and (len(self.document_set.all()) < 1)
        return False

# register pre_delete connector in order for the ModuleTerm to detect a
# cascaded/non-cascaded delete because overriding delete() is not enough
models.signals.pre_delete.connect(ModuleTerm.delete_handler)

class ModulePart(models.Model):
    """
    Model for a modulepart
    e.g. exercise, lecture, assignment, ...
    This references to a Module, not a ModuleTerm (which is the way the
    information is shown like).
    So every ModuleTerm of one Module transitively has the same ModuleParts
    """
    
    name = models.CharField(max_length=128)
    module = models.ForeignKey(Module)
    
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
    
    activated = models.BooleanField(default = False)
    
    date = models.DateField(auto_now_add = True)
    
    def get_short(self):
        """
        Makes the ModulePart short: Takes the upper case letters and numbers
        of the words an concatenates
        them (in lower case)
        'Vorlesungen und Script' => 'vs'
        """
        words = self.name.split()
        short = ''
        for word in words:
            letter = word[0:1]
            if(letter.isupper() or letter.isnumeric()):
                short = short + (word[0:1]).lower()
        return short
    
    def __unicode__(self):
        return self.name
    
    def has_perm(self, user_obj, perm):
        """
        Grants change/delete permission if the user has added the ModulePart and no item has been added yet
        """
        if (perm == 'documents.change_modulepart') or (perm == 'documents.delete_modulepart'):
            return (user_obj == self.user) and (len(self.document_set.all()) < 1)
        return False

class Document(models.Model):
    """    
    Model for a Document
    This represents a document (not a file - that is Upload) for a ModuleTerm
    and a ModulePart (e.g. WS2009, KuA Exercise)
    """
    name = models.CharField(max_length=128)
    tags = TaggableManager(blank=True)
    description = models.TextField(blank=True, null=True)
    module_part = models.ForeignKey(ModulePart)
    module_term = models.ForeignKey(ModuleTerm)
    
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
    
    activated = models.BooleanField(default = False)
    
    date = models.DateField(auto_now_add = True)
    
    def __unicode__(self):
        return self.name
    
    def has_perm(self, user_obj, perm):
        """
        Grants change/delete permission if the user has added the document and no item has been added yet
        """
        if (perm == 'documents.delete_document'):
            return (user_obj == self.user) and (len(self.item_set.all()) < 1)
        if (perm == 'documents.change_document'):
            return (user_obj == self.user)
        return False
    
class Item(models.Model):
    """        
    Model for an Item - belonging to a certain Document and having a ItemCategory
    Item is the class where all the extension possibilities lie.
    The upload app for example is based on this model (by referencing it)
    """
    
    comment = models.TextField(blank=True, null=True)
    datetime = models.DateTimeField(auto_now_add = True)
    views = models.IntegerField(default = 0)

    document = models.ForeignKey(Document)
    item_category = models.CharField(max_length=128, blank=True, null=True)
    
    user = models.ForeignKey(User)
    
    activated = models.BooleanField(default = False)
    
    item_type = ItemTypeField()

    
    def has_perm(self, user_obj, perm):
        """
        Grants change/delete permission if the user has added this item
        """
        if (perm == 'documents.change_item') or (perm == 'documents.delete_item'):
            return user_obj == self.user
        return False